#region imported Namespaces
using System;
using System.Data;
using SqlTypes = System.Data.SqlTypes;
using System.Collections.Specialized;
using System.Data.SqlClient;
using BO = PHSRAG.Insight21.BusinessObjects;
using Utility = PHSRAG.Utility;
using ICachePolicy = PHSRAG.Insight21.Policy.ICachePolicy;
using UserOrderType = PHSRAG.Insight21.Purchasing.UserOrderUtility.UserOrderType;
#endregion

namespace PHSRAG.Insight21.Purchasing
{
	#region Purchase Order Class
	/// <summary>
	/// Business class for the Purchase Order. It encapsulates the methods to 
	/// view, add, edit and delete a purchase order.
	/// </summary>
	public class PurchaseOrder: UserOrder
	{
		#region Constants
		private const int DefaultId						= 0;
		
		//Stored Procedure Parameter Name
		private const string RequisitionNumberParamName	= "@requisitionNumber";
		private const string VendorIDParamName			= "@vendorID";
		private const string VendorNameParamName		= "@vendorName";
		private const string VendorNumberParamName		= "@vendorNumber";
        private const string InvoiceNumberParamName     = "@invoiceNumber";
        private const string InvoiceDateParamName       = "@invoiceDate";
		
		//Data Column Names
		private const string RequistionNumberColumnName	= "RequisitionNumber";
		private const string VendorIDColumnName			= "VendorID";
		private const string VendorNameColumnName		= "VendorName";
		private const string VendorNumberColumnName		= "VendorNumber";
        private const string InvoiceNumberColumnName    = "InvoiceNumber";
        private const string InvoiceDateColumnName      = "InvoiceDate";
		
		//Stored Procedure Name
		private const string AddPOHeaderSPName			= "AddPOHeader";
		private const string UpdatePOHeaderSPName		= "UpdatePOHeader";
		
		#endregion	

		#region Instance Properties		
        /// <summary>
		/// Gets and sets the RequisitionNumber. Returns an empty string if value in datatable is DBNull.Value
		/// </summary>
		public string RequisitionNumber
		{
			get
			{
				object requisitionNumber = DataContainer.Tables[FirstDataTableIndex].Rows[0][RequistionNumberColumnName].ToString();
				return (requisitionNumber == DBNull.Value) ? string.Empty : requisitionNumber.ToString();
			}
			set { DataContainer.Tables[FirstDataTableIndex].Rows[0][RequistionNumberColumnName] = value; }
		}

		/// <summary>
		/// Gets and sets the VendorID. Returns DefaultId if value in datatable is DBNull.Value
		/// </summary>
		public int VendorID
		{
			get
			{
				object vendorID = DataContainer.Tables[FirstDataTableIndex].Rows[0][VendorIDColumnName];
				return (vendorID == DBNull.Value) ? DefaultId : (int)vendorID;
			}
			set { DataContainer.Tables[FirstDataTableIndex].Rows[0][VendorIDColumnName] = value; }
		}
		/// <summary>
		/// Gets and sets the VendorName. Returns empty string if value in datatable is DBNull.Value
		/// </summary>
		public string VendorName
		{
			get
			{
				object vendorName = DataContainer.Tables[FirstDataTableIndex].Rows[0][VendorNameColumnName];
				return (vendorName == DBNull.Value) ? string.Empty : vendorName.ToString();
			}
			set { DataContainer.Tables[FirstDataTableIndex].Rows[0][VendorNameColumnName] = value; }
		}

		/// <summary>
		/// Gets and sets the VendorNumber. Returns empty string if value in datatable is DBNull.Value
		/// </summary>
		public string VendorNumber
		{
			get
			{
				object vendorNumber = DataContainer.Tables[FirstDataTableIndex].Rows[0][VendorNumberColumnName];
				return (vendorNumber == DBNull.Value) ? string.Empty : vendorNumber.ToString();
			}
			set { DataContainer.Tables[FirstDataTableIndex].Rows[0][VendorNumberColumnName] = value; }
		}
		#endregion

		#region Constructor
		/// <summary>
		/// Initializes the base class with the specified cache policy
		/// </summary>
		/// <param name="cachePolicy">prevalent cache policy</param>
		public PurchaseOrder(ICachePolicy cachePolicy) : base(cachePolicy)
		{			
		}
		#endregion

		#region Public Methods
		/// <summary>
		/// Assigns values to the member variables of the current instance of purchase order.
		/// It checks for self assignment and calls the method in parent class to assign values
		/// to properties common to all user order types. Then it checks if the user order is of
		/// type voucher, if yes it gets the values from the properties common between voucher
		/// and purchase order.
		/// </summary>
		/// <param name="userOrder">existing instance of voucher or journal entry</param>
		/// <param name="orderType">new user order type desired</param>
		public override void AssignProperties(UserOrder userOrder, UserOrderType orderType)
		{
			if(!this.Equals(userOrder))
			{
				base.AssignProperties(userOrder, orderType);

				if(userOrder is Voucher)
				{
					Voucher voucher =	(Voucher)userOrder;
					VendorID		=	voucher.VendorID;
					VendorName		=	voucher.VendorName;
					VendorNumber	=	voucher.VendorNumber;					
				}
			}
		}

		/// <summary>
		/// Calls the virtual method in the base class to intialize the datacontainer and the
		/// data table for order header data and adds columns common to all user orders. In this
		/// method it adds column specific to purchase order to the table, adds an empty row in
		/// the table.
		/// </summary>
		public override void CreateHeaderTableAndAddRow()
		{
			base.CreateHeaderTableAndAddRow();

			DataTable orderHeader = DataContainer.Tables[Constants.UserOrderDetailsHeaderTableName];
            orderHeader.Columns.Add(InvoiceNumberColumnName, typeof(string));
            orderHeader.Columns.Add(InvoiceDateColumnName, typeof(string));
            orderHeader.Columns.Add(RequistionNumberColumnName, typeof(string));
			orderHeader.Columns.Add(VendorIDColumnName, typeof(int));
			orderHeader.Columns.Add(VendorNameColumnName, typeof(string));
			orderHeader.Columns.Add(VendorNumberColumnName, typeof(string));
			
			orderHeader.Rows.Add(orderHeader.NewRow());
		}

		/// <summary>
		/// Intializes the connection object, creates command if its not already created and 
		/// calls the methods to add and update user order header. The operations add and 
		/// update is done through single interface because this class uses the data adapter
		/// and dataSet. The dataSet knows its RowState, based on which it decides to use the 
		/// add or update command objects to perform the appropriate operation. After the
		/// operation is complete the business cache of dependent reports are uncached.
		/// </summary>
		/// <param name="connectionString">open connection object</param>
		/// <param name="args">optional parameters for the method, as of now nothing 
		/// is expected for this argument</param>
		public override void Save(string connectionString, params object[] args )
		{
			SqlConnection connection = new SqlConnection(connectionString);
			SqlTransaction transaction = null;
			try
			{
				connection.Open();
				VendorID = UserOrderHelper.GetVendorId(connection, VendorName, VendorNumber);
				LineItems.ValidateLineItems(connection);			
				
				if(!isCommandCreated)
					CreateCommands();
				
				transaction = connection.BeginTransaction();
				ExecuteUpdate(transaction);
				LineItems.Save(transaction, OrderID);
				transaction.Commit();
				UserOrderHelper.UnCacheDependentReports(CachePolicy);
			}
			catch(Exception ex)
			{
				if (transaction != null)
                    transaction.Rollback();
				throw(new Exception(@"Error in updating user order.", ex));
			}
			finally
			{
				if (connection.State != ConnectionState.Closed)
					connection.Close();
			}
		}
		#endregion		

		#region Protected Methods
		/// <summary>
		/// Creates the command objects for the add and update operation. 
		/// Calls the parent class method to initialize the command objects
		/// for add and update and add parameters to them. In this method, it
		/// sets the store procedures name specifc to purchase order for add and
		/// update commands and set the bool property isCommandCreated to true.
		/// </summary>
		protected override void CreateCommands()
		{
			base.CreateCommands();

			addCommand.CommandText = AddPOHeaderSPName;
            addCommand.Parameters.Add(InvoiceNumberParamName, SqlDbType.VarChar).SourceColumn = InvoiceNumberColumnName;
            addCommand.Parameters.Add(InvoiceDateParamName, SqlDbType.DateTime).SourceColumn = InvoiceDateColumnName;
            addCommand.Parameters.Add(RequisitionNumberParamName, SqlDbType.VarChar).SourceColumn = RequistionNumberColumnName;
			addCommand.Parameters.Add(VendorIDParamName, SqlDbType.Int).SourceColumn = VendorIDColumnName;
			addCommand.Parameters.Add(VendorNameParamName, SqlDbType.VarChar).SourceColumn = VendorNameColumnName;
			addCommand.Parameters.Add(VendorNumberParamName, SqlDbType.VarChar).SourceColumn = VendorNumberColumnName;

			updateCommand.CommandText = UpdatePOHeaderSPName;
            updateCommand.Parameters.Add(InvoiceNumberParamName, SqlDbType.VarChar).SourceColumn = InvoiceNumberColumnName;
            updateCommand.Parameters.Add(InvoiceDateParamName, SqlDbType.DateTime).SourceColumn = InvoiceDateColumnName;
            updateCommand.Parameters.Add(RequisitionNumberParamName, SqlDbType.VarChar).SourceColumn = RequistionNumberColumnName;
			updateCommand.Parameters.Add(VendorIDParamName, SqlDbType.Int).SourceColumn = VendorIDColumnName;
			updateCommand.Parameters.Add(VendorNameParamName, SqlDbType.VarChar).SourceColumn = VendorNameColumnName;
			updateCommand.Parameters.Add(VendorNumberParamName, SqlDbType.VarChar).SourceColumn = VendorNumberColumnName;
			isCommandCreated = true;
		}
		#endregion
	}
	#endregion
}
